目前为止,我们已经了解了用ProxyFactoryBean
或是相似的factory bean显示的创建AOP代理。
Spring也允许我们使用“自动代理的”bean定义,它会自动代理被选贼的bean。它基于Spring的“bean后置处理器”的结构,后置处理可以在容器加载bean时修改bean的定义。
在这个模块,你在XML中定义了一些特殊的bean用来配置自动代理结构。这是你只需声明自动代理的目标,而不再需要使用ProxyFactoryBean
。
有两种方式可以实现这点:
使用自动代理创造器并引用当前上下文中的特殊的bean。
特殊的自动代理创建需要被单独处理;自动代理创建由源码级别的元数据属性驱动。
org.springframework.aop.framework.autoproxy
包提供下列标准的自动代理创造器。
BeanNameAutoProxyCreator
类是一个BeanPostProcesser
,可以为名字匹配字面值或是通配符的bean自动创建AOP代理。
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames" value="jdk*,onlyJdk"/>
<property name="interceptorNames">
<list>
<value>myInterceptor</value>
</list>
</property>
</bean>
和ProxyFactoryBean
一样,它采用interceptorNames
属性,而不是interceptor的数组,保证原型的advisor行为正确。这里的"interceptor"可以使advisors或任何advice类型。
和通常的自动代理一样,使用BeanNameAutoProxyCreator
的重点是将相同的配置应用到多个对象上,到达最小配置的目的。对于在多个对象上应用声明性事务时,它是很常见的选择。
对于名字匹配的bean定义,比如上面例子中的"jdkMyBean"和"onlyJdk",就是普通的Bean定义的目标类。BeanNameAutoProxyCreator
会自动的创建AOP代理。同一个通知会应用到匹配的bean上。注意如果使用的是advisor(而不是上例中的interceptor),那么可以对不同的bean应用不同的切点。
更加常见和强大的自动代理创造器是DefaultAdvisorAutoProxyCreator
。它会自动自动应用上下文中合格的advisor,不再需要指定advisor的bean定义。它和BeanNameAutoProxyCreator
一样具有应用相同的配置到多个对象上的有点。
使用这个机制涉及:
指定一个DefaultAdvisorAutoProxyCreator
bean定义。
在用一个或想关联的上下文中指定一些Advisors。注意一定要是Advisor,而非interceptor或是advice。这是因为它要指明切点,并为每个通知检查合格的候选Bean定义。
DefualtAdvisorAutoProxyCreator
会自动评估每个advisor中定义的切点,来确定为每个业务对象(比如"businessObject1"和"businessObject2")应用什么通知(如果存在的话)。
这意味着通知都会被应用到业务对象上。如果任何advisor中的切点都不匹配业务对象的方法,那将不会有对象被代理。如果有新添加的业务对象的bean定义,且匹配advisor,它们会自动被代理。
通常,自动代理具有让调用者无法获取未被通知的对象的特点。在这个上下文环境中使用getBean("businessObject1")会返回一个AOP代理,而不是目标的业务对象。(之前说的“内部bean”的方式也有这个好处)。
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
<property name="transactionInterceptor" ref="transactionInterceptor"/>
</bean>
<bean id="customAdvisor" class="com.mycompany.MyAdvisor"/>
<bean id="businessObject1" class="com.mycompany.BusinessObject1">
<!-- Properties omitted -->
</bean>
<bean id="businessObject2" class="com.mycompany.BusinessObject2"/>
DefualtAdvisorAutoProxyCreator
在你想讲同一个通知应用到多个业务对象上时十分有效。一旦结构定义确定,你可以简单的田间新的业务对象而不用在指定代理的配置。你也可以很简单的添加其他的切面——比如,追踪或是监测性能的切面——只需要改动很小的配置。
DefaultAdvisorAutoProxyCreator支持过滤(对名字进行约束,只有符合的advisor会被评估,在同一个工厂中,可以使用多个不同配置的AdvisorAutoProxyCreator)和排序。Advisor可以实现org.springframework.core.Ordered
接口来保证正确的顺序。上面例子中的TransactionAttributeSourceAdvisor已经配置了order值;more的设置未被排序的。
它是DefaultAdvisorAutoProxyCreator的父类。你可以用它创建自己的自动代理创造器,在少数的一些情况下,弥补框架提供的DefaultAdvisorAutoProxyCreator
的不足。
一种特别重要的自动代理类型是由元数据驱动的。这和.NET的ServicedComponents
是相似的编程模型。和在XML中定义元数据不同,事务管理和其他企业服务定义在源码级别的属性上。
这种情况下,你可以结合了解元数据属性的Advisor使用DefaultAdvisorAutoProxyCreator
。元数据信息定义在候选的advisor的切点部分,而不是在自动代理创建类本身。
这实际上是DefaultAdvisorAutoProxyCreator
的一个特例,但是值得去思考。(知道元数据的代码在advisor包含的切点中,而不是AOP框架自身。)
JPetStore示例应用(sun公司为了演示自己的J2EE而编写的一个宠物店的电子商务的例子)的/attributes
目录展示了属性驱动的自动代理。这种情况下,没有必要使用TransactionProxyFactoryBean
。由于使用了metadata-aware(了解元数据)的切点,简单的在业务对象上定义事务属性就足够了。在/WEB-INF/declarativeServices.xml
中的bean定义包含了下面的代码。注意这都是通用的,可以在JPetStore之外使用:
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
<property name="transactionInterceptor" ref="transactionInterceptor"/>
</bean>
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributeSource">
<bean class="org.springframework.transaction.interceptor.AttributesTransactionAttributeSource">
<property name="attributes" ref="attributes"/>
</bean>
</property>
</bean>
<bean id="attributes" class="org.springframework.metadata.commons.CommonsAttributes"/>
DefaultAdvisorAutoProxyCreator
bean定义(名字不重要,因此被省略了)会自动在当前的上下文中选择符合的切点。在这个情况下,TranscationAttributeSourceAdvisor
类型的"transcationAdvisor"bean定义,会被应用到带有transaction属性的类或者方法上。TransactionAttributeSourceAdvisor通过构造器依赖,依赖于TransactionInteceptor。这个例子通过自动装配解决了依赖问题。AttributesTransactiobnAttributeSource
依赖于org.springframework.metadata.Attributes
的接口的实现。在这里,"attributes"bean满足这个条件,它通过Jakarta Commons Attributes API来获取属性信息。(银行用程序代码必须已经被Commons Attributes 编译任务编译过。)
JPetStore示例应用的/annotation
目录包含了一个相似的自动代理的例子,它由JDK1.5+注解驱动。下面的配置开启Spring的Transactional
注解的自动检测,为包含该注解的bean隐式的创建代理。
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
<property name="transactionInterceptor" ref="transactionInterceptor"/>
</bean>
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributeSource">
<bean class="org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"/>
</property>
</bean>
这里定义的TransactionInterceptor
依赖于PlatformTranscationManager
的定义,这个定义通常不在这个文件中(尽管它可以在这里定义),因为它取决于应用程序的事务要求(通常是 JTA,或Hibernate,或JDO或JDBC):
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager"/>
如果你只需要声明事务管理,那么使用这些通用的XML定义会让Spring自动为所有具有事务属性的类和方法创建代理。你不需要直接和AOP打交道,这样的编程模型和.NET的ServicedComponents是很相似的。
这种机制是可拓展的。可以让自定义的属性创建自动代理。你只需要:
定义你自己的属性。
注定一个advisor,它有必要的通知,并且有一个会被含有自定属性的类或方法触发的切点。
这些的advisor可以对每个被通知的类都是不同的(比如,mixins):可以将advisor定义为原型,而不是单例。比如,之前所演示的Spring test包LockMixin
引入拦截器,可以结合通用的DefaultIntroductionAdvisor
使用:
<bean id="lockMixin" class="test.mixin.LockMixin" scope="prototype"/>
<bean id="lockableAdvisor" class="org.springframework.aop.support.DefaultIntroductionAdvisor"
scope="prototype">
<constructor-arg ref="lockMixin"/>
</bean>
注意:lockMixin
和lockableAdvisor
都被定义成了原型。